//
//  JwHttpManager.m
//  JwPack
//
//  Created by 陈警卫 on 2024-08-29.
//

#import "JwHttpManager.h"

@implementation JwHttpManager

/// 单例
+ (JwHttpManager *)shared {
    static JwHttpManager *sharedObject;
    static dispatch_once_t token;
    dispatch_once(&token, ^{
        sharedObject = [[JwHttpManager alloc] initShared];
    });
    return sharedObject;
}

- (instancetype)init {
    return [[self class] shared];
}

- (instancetype)initShared {
    self = [super init];
    if (self) {
        [self setupData];
    }
    return self;
}

- (void)setupData {
    self.condition = [[NSCondition alloc] init];
    self.lock = NO;
    
    self.handleClass = [JwHttpHandel class];
    self.baserClass = [JwHttpBaser class];
}

- (AFHTTPSessionManager *)httpSession {
    if (!_httpSession) {
        NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
        config.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
        config.URLCache = nil;
        AFHTTPSessionManager *session = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config];
        session.requestSerializer = [AFJSONRequestSerializer serializer];
        session.requestSerializer.timeoutInterval = 20;
        session.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
        session.responseSerializer = [AFJSONResponseSerializer serializer];
        NSSet *types = [NSSet setWithObjects:
                        @"text/html",
                        @"text/json",
                        @"application/json",
                        @"text/plain",
                        @"text/javascript", nil];
        session.responseSerializer.acceptableContentTypes = types;
        _httpSession = session;
    }
    return _httpSession;
}

- (NSString *)fileCompleFolderPath {
    if (!_fileCompleFolderPath) {
        NSString *cachesPath = [JwFile cachesPath];
        NSString *complePath = [cachesPath stringByAppendingPathComponent:@"jwdown"];
        [JwFile createFolder:complePath];
        _fileCompleFolderPath = complePath;
    }
    return _fileCompleFolderPath;
}

/// 获取文件保存名称(保留后缀名处理)
- (NSString *)fileCachesNameWithFileURL:(NSURL *)URL name:(NSString *)name {
    NSString *filename = [URL lastPathComponent];
    if (name) {
        if ([name containsString:@"."]) {
            filename = name;
        } else {
            NSString *format = [filename componentsSeparatedByString:@"."].lastObject;
            if (format.length > 0) {
                filename = [NSString stringWithFormat:@"%@.%@", name, format];
            }
        }
    }
    return filename;
}

/// 获取文件临时存储路径URL(保留后缀名处理)
/// URL: 文件请求
/// name: 文件自定名称
- (NSURL *)fileCachesURLWithFileURL:(NSURL *)URL name:(NSString *)name {
    NSString *filename = [self fileCachesNameWithFileURL:URL name:name];
    NSString *cachesPath = [JwFile cachesPath];
    NSString *fileCachesPath = [cachesPath stringByAppendingPathComponent:filename];
    NSURL *fileCachesURL = [NSURL URLWithString:fileCachesPath];
    return fileCachesURL;
}

/// 下载
- (NSURLSessionDownloadTask *)downloadWithConfig:(JwHttpConfig *)config comple:(void (^)(JwHttpConfig *config))comple {
    NSURL *URL = [NSURL URLWithString:config.url];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    NSURL *fileCachesURL = [self fileCachesURLWithFileURL:URL name:nil];
    NSString *targetPath = [self.fileCompleFolderPath stringByAppendingPathComponent:[fileCachesURL lastPathComponent]];
    
    NSURLSessionDownloadTask *task;
    
    if (config.downPolicy == JwHttpDownPolicyCaches) {
        if ([JwFile fileExist:targetPath]) {
            config.state = JwHttpStateResponse;
            config.filePathURL = [NSURL URLWithString:targetPath];
            if ([config.owners[kJwHttpOwnerDebugLogKey] isEqualToString:@"1"]) {
                DLog(@"%@--%@--%@--%@", config.url, config.headers, config.params, config.filePathURL);
            }
            if (comple) {
                comple(config);
            }
        }
        return task;
    }
    
    kJwBlock(task);
    kJwBlock(config);
    task = [self.httpSession downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        bconfig.state = JwHttpStateProgress;
        bconfig.progress = downloadProgress;
        if ([bconfig.owners[kJwHttpOwnerDebugLogKey] isEqualToString:@"1"]) {
            DLog(@"%@", bconfig.progress);
        }
        if (comple) {
            comple(bconfig);
        }
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        
        return fileCachesURL;
        
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        if (error) {
            [btask cancel];
            [[NSFileManager defaultManager] removeItemAtPath:[filePath path] error:nil];
            bconfig.state = JwHttpStateError;
            bconfig.error = error;
            if ([bconfig.owners[kJwHttpOwnerDebugLogKey] isEqualToString:@"1"]) {
                DLog(@"%@--%@--%@--%@", bconfig.url, bconfig.headers, bconfig.params, bconfig.error);
            }
            if (comple) {
                comple(bconfig);
            }
        } else {
            [[NSFileManager defaultManager] moveItemAtPath:[filePath path] toPath:targetPath error:nil];
            DLog(@"jwdown--%@", targetPath);
            bconfig.state = JwHttpStateResponse;
            bconfig.filePathURL = [NSURL URLWithString:targetPath];
            if ([bconfig.owners[kJwHttpOwnerDebugLogKey] isEqualToString:@"1"]) {
                DLog(@"%@--%@--%@--%@", bconfig.url, bconfig.headers, bconfig.params, bconfig.filePathURL);
            }
            if (comple) {
                comple(bconfig);
            }
        }
    }];
    [task resume];
    return task;
}

- (NSURLSessionDataTask *)uploadWithConfig:(JwHttpConfig *)config comple:(void (^)(JwHttpConfig *config))comple {
    kJwBlock(config);
    return [self.httpSession POST:config.url parameters:config.params headers:config.headers constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        // name: 参数名 fileName: 文件名
        if (config.dataParams) {
            NSArray *imageKeys = config.dataParams.allKeys;
            CGFloat timeInterval = [[NSDate date] timeIntervalSince1970];
            for (NSInteger i = 0; i < imageKeys.count; i++) {
                NSString *key = imageKeys[i];
                id value = config.dataParams[key];
                NSString *name = [NSString stringWithFormat:@"%f-%ld", timeInterval, i];
                
                if ([value isKindOfClass:[UIImage class]]) {
                    NSData *data = UIImageJPEGRepresentation(value, 0.5);
                    DLog("upload image.data--%lu", data.length);
                    [formData appendPartWithFileData:data name:key fileName:name mimeType:@"image/jpeg"];
                } else if ([value isKindOfClass:[NSURL class]]) {
                    NSURL *url = value;
                    [formData appendPartWithFileURL:url name:key error:nil];
                }
            }
        }
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        bconfig.state = JwHttpStateProgress;
        bconfig.progress = uploadProgress;
        if ([bconfig.owners[kJwHttpOwnerDebugLogKey] isEqualToString:@"1"]) {
            DLog(@"%@", bconfig.progress);
        }
        if (comple) {
            comple(bconfig);
        }
    } success:config.success failure:config.failure];
}

/// 请求
- (void)requestWithConfig:(JwHttpConfig *)config comple:(void (^)(JwHttpConfig *config))comple {
    kJwBlock(config);
    
    void (^success)(NSURLSessionDataTask *task, id _Nullable responseObject) = ^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        bconfig.state = JwHttpStateResponse;
        bconfig.task = task;
        bconfig.response = responseObject;
        if ([bconfig.owners[kJwHttpOwnerDebugLogKey] isEqualToString:@"1"]) {
            DLog(@"%@--%@--%@--%@", bconfig.url, bconfig.headers, bconfig.params, bconfig.response);
        }
        if (comple) {
            comple(bconfig);
        }
    };
    void (^failure)(NSURLSessionDataTask * _Nullable task, NSError *error) = ^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        bconfig.state = JwHttpStateError;
        bconfig.task = task;
        bconfig.error = error;
        if ([bconfig.owners[kJwHttpOwnerDebugLogKey] isEqualToString:@"1"]) {
            DLog(@"%@--%@--%@--%@", bconfig.url, bconfig.headers, bconfig.params, bconfig.error);
        }
        if (comple) {
            comple(bconfig);
        }
    };
    
    config.comple = comple;
    config.success = success;
    config.failure = failure;
    
    config.state = JwHttpStateStart;
    if (comple) {
        comple(config);
    }
    
    if ([config.owners[kJwHttpOwnerDebugLogKey] isEqualToString:@"1"]) {
        DLog(@"%@--%@--%@", config.url, config.headers, config.params);
    }
    
    NSURLSessionDataTask *task;
    NSURLSessionDownloadTask *downloadTask;
    
    if ([config.method isEqualToString:kJwHttpMethodUPLOAD]) {
        task = [self uploadWithConfig:config comple:comple];
    } else if ([config.method isEqualToString:kJwHttpMethodDOWNLOAD]) {
        downloadTask = [self downloadWithConfig:config comple:comple];
    } else {
        task = [self.httpSession dataTaskWithHTTPMethod:config.method
                                              URLString:config.url
                                             parameters:config.params
                                                headers:config.headers
                                         uploadProgress:nil
                                       downloadProgress:nil
                                                success:success
                                                failure:failure];
        [task resume];
    }
    config.state = JwHttpStateRequest;
    config.task = task;
    config.downloadTask = downloadTask;
    
    if (comple) {
        comple(config);
    }
}

/// 请求
- (JwHttpConfig *)request:(kJwHttpMethod *)method
                      url:(nullable NSString *)url
                    point:(nullable NSString *)point
                   params:(nullable NSDictionary *)params
                  headers:(nullable NSDictionary *)headers
                   owners:(nullable NSDictionary *)owners
                   comple:(void (^)(JwHttpConfig * config))comple {
    JwHttpConfig *config = [JwHttpConfig configWithMethod:method point:point url:url params:params headers:headers owners:owners];
    [self requestWithConfig:config comple:comple];
    return config;
}

/// 请求
- (JwHttpConfig *)request:(kJwHttpMethod *)method
                    point:(nullable NSString *)point
                   params:(nullable NSDictionary *)params
                  headers:(nullable NSDictionary *)headers
                   owners:(nullable NSDictionary *)owners
                   comple:(void (^)(JwHttpConfig * config))comple {
    return [self request:method url:nil point:point params:params headers:headers owners:owners comple:comple];
}

/// 请求(异步带锁)
- (void)requestLockWithConfig:(JwHttpConfig *)config comple:(void (^)(JwHttpConfig *config))comple {
    kJwBlock(config);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self.condition lock];
        
        BOOL nLock = [config.owners[kJwHttpOwnerNoLockKey] isEqualToString:@"1"];
        if (self.lock && !nLock) {
            [self.condition wait];
        }
        
        Class class = self.baserClass;
        if ([config.owners[kJwHttpOwnerRefreshParamsKey] isEqualToString:@"1"]) {
            config.params = [class setupBaseParamsWithParam:config.params];
        }
        if ([config.owners[kJwHttpOwnerRefreshHeadersKey] isEqualToString:@"1"]) {
            config.headers = [class setupBaseHeadersWithParam:config.headers];
        }
        
        [self requestWithConfig:bconfig comple:^(JwHttpConfig * _Nonnull config) {
            dispatch_async(dispatch_get_main_queue(), ^{
                comple(config);
            });
        }];
        [self.condition unlock];
    });
}

/// 请求(异步带锁)
- (JwHttpConfig *)requestLock:(kJwHttpMethod *)method
                          url:(nullable NSString *)url
                        point:(nullable NSString *)point
                       params:(nullable NSDictionary *)params
                      headers:(nullable NSDictionary *)headers
                       owners:(nullable NSDictionary *)owners
                       comple:(void (^)(JwHttpConfig * config))comple {
    JwHttpConfig *config = [JwHttpConfig configWithMethod:method point:point url:url params:params headers:headers owners:owners];
    [self requestLockWithConfig:config comple:comple];
    return config;
}

/// 请求(异步带锁)
- (JwHttpConfig *)requestLock:(kJwHttpMethod *)method
                        point:(nullable NSString *)point
                       params:(nullable NSDictionary *)params
                      headers:(nullable NSDictionary *)headers
                       owners:(nullable NSDictionary *)owners
                       comple:(void (^)(JwHttpConfig * config))comple {
    return [self requestLock:method url:nil point:point params:params headers:headers owners:owners comple:comple];
}

/// 请求(异步带锁及逻辑处理)
- (void)requestHandelWithConfig:(JwHttpConfig *)config comple:(void (^)(JwHttpConfig * config))comple {
    [self requestLockWithConfig:config comple:^(JwHttpConfig *config) {
        [self.handleClass handelViewWithConfig:config];
        if (config.state == JwHttpStateRequest) {

        } else if (config.state == JwHttpStateResponse) {
            [self.handleClass handelShouldSuccessWithConfig:config];
        } else if (config.state == JwHttpStateError) {
            [self.handleClass handelErrorHttpWithConfig:config];
        }
        if (comple) {
            comple(config);
        }
    }];
}

/// 请求(异步带锁及逻辑处理)
- (JwHttpConfig *)requestHandel:(kJwHttpMethod *)method
                            url:(nullable NSString *)url
                          point:(nullable NSString *)point
                         params:(nullable NSDictionary *)params
                        headers:(nullable NSDictionary *)headers
                         owners:(nullable NSDictionary *)owners
                decodeModelName:(nullable NSString *)decodeModelName
                     decodePath:(nullable NSString *)decodePath
                         comple:(void (^)(JwHttpConfig * config))comple {
    JwHttpConfig *config = [JwHttpConfig configWithMethod:method point:point url:url params:params headers:headers owners:owners];
    config.decodeModelName = decodeModelName;
    config.decodePath = decodePath;
    [self requestHandelWithConfig:config comple:comple];
    return config;
}

/// 请求(异步带锁及逻辑处理)
- (JwHttpConfig *)requestHandel:(kJwHttpMethod *)method
                          point:(nullable NSString *)point
                         params:(nullable NSDictionary *)params
                        headers:(nullable NSDictionary *)headers
                         owners:(nullable NSDictionary *)owners
                decodeModelName:(nullable NSString *)decodeModelName
                     decodePath:(nullable NSString *)decodePath
                         comple:(void (^)(JwHttpConfig * config))comple {
    return [self requestHandel:method url:nil point:point params:params headers:headers owners:owners decodeModelName:decodeModelName decodePath:decodePath comple:comple];
}


@end
